package twoD.IsoPfem.EmbeddedCrackModel;

import inf.jlinalg.SolveFailedException;
import inf.v3d.view.Viewer;

import java.util.ArrayList;

import twoD.IsoPfem.Constraint;
import twoD.IsoPfem.EdgeLoad;
import twoD.IsoPfem.Force;
import twoD.IsoPfem.IGeometry;
import twoD.IsoPfem.ElasticStructure;
import twoD.IsoPfem.Mesh;
import twoD.IsoPfem.MeshLibrary;
import twoD.IsoPfem.Node;
import twoD.IsoPfem.RealTable;
import twoD.IsoPfem.Visualizer;
import twoD.IsoPfem.Control.ArcLengthController;
import twoD.IsoPfem.Control.DisplacementConstraintCondition;
import twoD.IsoPfem.Control.IConstraintCondition;
import twoD.IsoPfem.Control.LoadConstraintCondition;
import twoD.IsoPfem.Control.SphereConstraintCondition;
import twoD.IsoPfem.math.FunctionRToR;
import twoD.IsoPfem.math.Interval;
import twoD.IsoPfem.utils.MeshUtilities;
import twoD.IsoPfem.utils.NodeUtilities;

public class SlabSpecimenDemo {

	/**
	 * function to visualize the structure
	 * 
	 * @param struct
	 */
	public void Visualize(ElasticStructure struct) {
		Viewer view = new Viewer();
		Visualizer viz = new Visualizer(struct, view);
		viz.automaticScale();
		viz.drawConstraints();
		viz.drawForces();
		viz.drawEdgeLoads();
		viz.drawElements();
		view.setVisible(true);
	}

	/**
	 * function to draw structure with cracks
	 * 
	 * @param struct
	 */
	public void VisualizeWithCrack(CrackStructure struct) {
		Viewer view = new Viewer();
		CrackVisualizer viz = new CrackVisualizer(struct, view);
		viz.automaticScale();
		viz.drawConstraints();
		viz.drawForces();
		viz.drawEdgeLoads();
		viz.drawElements();
		viz.drawCrack();
		view.setVisible(true);
	}

	/**
	 * function to create structure for crack computation. We should not change
	 * the parameters inside this is the simplest tets with 1 element
	 * 
	 * @return
	 */
	public void crackTest1() {
		Mesh M = MeshLibrary.createMesh1();

		double E = 30e9;
		double nu = 0.18;
		double ft = 2.9e6;
		double Gf = 140;
		double r = 1e5;
		double s = 1e-7;
		double psi = 0;
		double lambda0 = 11.3;
		int N = 4;

		double Dnn = 0.01 * E;
		double Dss = 0.01 * E;

		RealTable realTable = new RealTable(E, nu, Dnn, Dss);
		realTable.setThickness(1);
		realTable.setTensileStrength(ft);
		realTable.setFractureEnergy(Gf);

		CrackStructure cStruct = MeshLibrary.createEmbededCrackModel(realTable,
				M);

		/*
		 * need to call this to use any routine related to dof numbers
		 */
		cStruct.enumerateDOFs();

		IConstraintCondition cc1 = new LoadConstraintCondition(1, 0.1);
		IConstraintCondition cc2 = new DisplacementConstraintCondition(4.5e-3,
				1e-4, NodeUtilities.findNode(cStruct, 1, 0.5).get(0)
						.getDofNumbers());
		IConstraintCondition cc3 = new SphereConstraintCondition(s, psi,
				NodeUtilities.findNode(cStruct, 1, 0.5).get(0).getDofNumbers());
		cc3.setInitialLambda(lambda0);

		ArcLengthController C = new ArcLengthController(cStruct, cc3);
		C.setNumberOfStep(N);
		try {
			C.Iterate();
		} catch (SolveFailedException e) {
			e.printStackTrace();
		}
		// C.listingState();

		// VisualizeWithCrack(cStruct);

		// Plot1D p = new Plot1D(C);
		// p.setN(N);
		// p.setVisible(true);
	}

	private double[][] geomData = { { 22, 22, 2, 2, 6 }, { 6, 6, 2, 2, 2 },
			{ 62, 22, 2, 2, 6 } };

	public CrackStructure crackTest2(int[] numStep) {
		double[] data = geomData[0];

		double l = data[0];
		double h = data[1];
		double t = data[2];
		double dt = data[3];
		double c = data[4];

		Mesh M = MeshLibrary.createMesh2(l, h, t, dt, c);

		double E = 50e9;
		double nu = 0.2;
		double Dnn = 0.01 * E;
		double Dss = 0.01 * E;

		RealTable realTable = new RealTable(E, nu, Dnn, Dss);
		realTable.setThickness(1);
		realTable.setTensileStrength(2.9e6);
		realTable.setFractureEnergy(70);

		CrackStructure cStruct = MeshLibrary.createEmbededCrackModel(realTable,
				M);

		Constraint c1 = new Constraint(false, false);
		Constraint c2 = new Constraint(true, false);

		NodeUtilities.findNode(cStruct, 0.0, 0.0).get(0).setConstraint(c1);
		NodeUtilities.findNode(cStruct, l, 0.0).get(0).setConstraint(c2);

		Node n1 = NodeUtilities.findNode(cStruct, (l - t) / 2, h).get(0);
		Node n2 = NodeUtilities.findNode(cStruct, (l - t) / 2 + t, h).get(0);

		EdgeLoad el = new EdgeLoad(n1, n2, new FunctionRToR() {

			@Override
			public double valueAt(double x) {
				return -2e6;
			}

			@Override
			public int getP() {
				return 0;
			}

			@Override
			public Interval getDomain() {
				return new Interval(0, 1);
			}

			@Override
			public double[] getBreakpoints() {
				return null;
			}

			@Override
			public double derivativeAt(double x) {
				return 0;
			}
		});

		cStruct.enumerateDOFs();
		// in order to find elements, we have to enumerate first
		ArrayList<Integer> tmp = MeshUtilities.findElement(cStruct, n1, n2);
		for (int i : tmp)
			cStruct.getElements(i).addEdgeLoad(el);

		/*
		 * for geom[1] choose 35 for geom[0] choose 65; 150
		 */
		numStep[0] = 150;
		return cStruct;
	}

	public CrackStructure crackTest3(int[] numStep) {
		Mesh M = MeshLibrary
				.createTriangleMeshFromGiD("D:/Giang/vgu/zWork/simple_beam.gid/mesh3.txt");

		double E = 50e9;
		double nu = 0.2;
		double Dnn = 0.01 * E;
		double Dss = 0.01 * E;

		RealTable realTable = new RealTable(E, nu, Dnn, Dss);
		realTable.setThickness(1);
		realTable.setTensileStrength(2.9e6);
		realTable.setFractureEnergy(70);

		CrackStructure cStruct = MeshLibrary.createEmbededCrackModel(realTable,
				M);

		for (IGeometry g : M.getGeometries()) {
			cStruct.addElement(new EmbeddedCrackCST(realTable, g));
		}

		Constraint c1 = new Constraint(false, false);
		Constraint c2 = new Constraint(true, false);

		NodeUtilities.findNode(cStruct, 0.0, 0.0).get(0).setConstraint(c1);
		NodeUtilities.findNode(cStruct, 100.0, 0.0).get(0).setConstraint(c2);

		Force f = new Force(0, -1e7);
		NodeUtilities.findNode(cStruct, 50.0, 40.0).get(0).setForce(f);

		numStep[0] = 33;
		return cStruct;
	}

	public void crackTest4() {
		Mesh M = MeshLibrary
				.createTriangleMeshFromGiD("D:/Giang/vgu/zWork/simple_beam.gid/mesh3.txt");

		double E = 50e9;
		double nu = 0.2;
		double Dnn = 0.01 * E;
		double Dss = 0.01 * E;

		RealTable realTable = new RealTable(E, nu, Dnn, Dss);
		realTable.setThickness(1);
		realTable.setTensileStrength(2.9e6);
		realTable.setFractureEnergy(70);

		CrackStructure cStruct = MeshLibrary.createEmbededCrackModel(realTable,
				M);

		Constraint c1 = new Constraint(false, false);
		Constraint c2 = new Constraint(true, false);

		NodeUtilities.findNode(cStruct, 0.0, 0.0).get(0).setConstraint(c1);
		NodeUtilities.findNode(cStruct, 100.0, 0.0).get(0).setConstraint(c2);

		Force f = new Force(0, -1e7);
		final Node forceNode = NodeUtilities.findNode(cStruct, 50.0, 40.0).get(
				0);
		forceNode.setForce(f);

		IConstraintCondition cc1 = new LoadConstraintCondition(1, 0.1);
		IConstraintCondition cc2 = new DisplacementConstraintCondition(1e-3,
				5e-4, forceNode.getDofNumbers()[1]);
		IConstraintCondition cc3 = new SphereConstraintCondition(3e-4, 1e-3,
				forceNode.getDofNumbers()[1]);
		ArcLengthController C = new ArcLengthController(cStruct, cc3);
		// set 10 for load control/displacement control
		C.setNumberOfStep(12);
		try {
			C.Iterate();
		} catch (SolveFailedException e) {
			e.printStackTrace();
		}
		C.listingState();

		VisualizeWithCrack(cStruct);
	}

	public static void main(String[] args) {
		new SlabSpecimenDemo().crackTest1();
	}

}
